from pydantic import BaseModel, Field, validator
import bson
from bson.objectid import ObjectId
from datetime import datetime
from app.libs.enums import MONITOR_TYPE_TUPLE
from app.errors import ParameterError


class PydanticObjectId(ObjectId):
    """python objectid 校验"""
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise TypeError('ObjectId required')
        return ObjectId(v)


class _DateTime(BaseModel):
    """共用的日期范围查询字段"""
    startTime: datetime = Field(None, title='开始时间')
    endTime: datetime = Field(None, title='结束时间')

    @validator('startTime')
    def validate_start_time(cls, v):
        return {'$gte': v}

    @validator('endTime')
    def validate_end_time(cls, v):
        return {'$lte': v}


class _Extra(BaseModel):
    """查询控制字段"""
    limit: int = Field(None, title='返回条目限制')
    sort: str = Field(None, title='排序字段')

    @validator('sort')
    def validate_sort(cls, v):
        """+_id,-datetime order_by ('+_id', '-datetime') （默认 + 升序） （- 降序）"""
        return v.strip().split(',')


class _TaskType(BaseModel):
    """对于 weakness available 改为调用两次接口分别获取"""
    taskType: str = Field(None, title='监测类型')

    @validator('taskType')
    def validate(cls, v):
        if v in MONITOR_TYPE_TUPLE:
            return v
        raise Exception('非监测类型值')


class _ReqField(BaseModel):
    req_fields: str = Field(None, title='请求返回字段')

    @validator('req_fields')
    def validate_req_field(cls, field):
        return field.strip().split(',')


class TaskSchema(_TaskType, _ReqField, _Extra):
    """task表 筛选条件"""
    jobId: str = Field(None, name='job Id')
    target: str = Field(None, title='域名查询')
    range: str = Field()
    startTime: str = Field(None)
    endTime: str = Field(None)
    pk: str = Field(None)

    @validator('jobId')
    def validate_jobId(cls, v):
        try:
            return ObjectId(v)
        except bson.errors.InvalidId:
            raise ParameterError(msg="jobId format error")

    @validator('pk')
    def validate_pk(cls, v):
        return ObjectId(v)
